package org.papervision3d.core.culling {
	
	import flash.geom.Rectangle;	
	
	import org.papervision3d.core.geom.renderables.Line3D;	
	import org.papervision3d.core.culling.ILineCuller;
	
	import org.papervision3d.core.math.util.FastRectangleTools;	
	
	
	/**
	 * @author Seb Lee-Delisle
	 */
	public class RectangleLineCuller implements ILineCuller {

		private var cullingRectangle : Rectangle;
		private var lineBoundsRect : Rectangle;
		
		// temporary rectangle to avoid object creation. 
		private var rectIntersection : Rectangle; 
		
		/**
		 * @Author Seb Lee-Delisle
		 *
		 * RectangleLineCuller
		 * 
		 * <span lang="ja">このラインカラ―は、ビューポートに交差するかどうかに基づいてラインをカリングします。</span>
		 * <span lang="en">This Line Culler culls lines based upon whether they intersect the viewport rectangle.</span>
		 */
		 
		public function RectangleLineCuller(cullingRectangle:Rectangle = null):void
		{
			if(cullingRectangle){
				this.cullingRectangle = cullingRectangle;	
			}
			lineBoundsRect = new Rectangle(); 
			rectIntersection = new Rectangle(); 
		}
		public function testLine(line : Line3D) : Boolean 
		{
			
			// if one or more of the points is behind the camera, then cull. 
			if((!line.v0.vertex3DInstance.visible)||(!line.v1.vertex3DInstance.visible)) return false; 

			var l0x : Number = line.v0.vertex3DInstance.x; 
			var l0y : Number = line.v0.vertex3DInstance.y;
			var l1x : Number = line.v1.vertex3DInstance.x;
			var l1y : Number = line.v1.vertex3DInstance.y;

			// get the line bounds rect 
			lineBoundsRect.width = Math.abs(l1x-l0x);
			lineBoundsRect.height = Math.abs(l1y-l0y);
			
			if(l0x<l1x) lineBoundsRect.x = l0x; 
			else lineBoundsRect.x = l1x; 
			
			if(l0y<l1y) lineBoundsRect.y = l0y; 
			else lineBoundsRect.y = l1y; 
			
			if(cullingRectangle.containsRect(lineBoundsRect)) return true; 
			if(!FastRectangleTools.intersects(lineBoundsRect,cullingRectangle)) return false; 
			
			rectIntersection = FastRectangleTools.intersection(lineBoundsRect, cullingRectangle);
			
			// calculate the equation of the line using the function y = mx + c
			// m is the gradiant
			var m:Number = (l1y-l0y)/(l1x-l0x);
			
			// so if y=mx +c then 
			// l0y = m * l0x +c
			// so... 
			var c:Number = l0y - (m*l0x);
			
			// so now find the point where the line crosses the top of the rectangle
			// y = mx +c; 
			// so also 
			// x = (y - c) / m ; 
			// 
			
			var xcross:Number = (cullingRectangle.top - c)/m;
			
			
			if((xcross>rectIntersection.left) && (xcross<rectIntersection.right)) 
			{
				return true;
			} 
			
			// and the bottom of the rectangle
			xcross = (cullingRectangle.bottom - c)/m;
			if((xcross>rectIntersection.left) && (xcross<rectIntersection.right)) 
			{
				return true; 
			}
			
			// and the left
			var ycross:Number = (m * cullingRectangle.left) +c;
			if((ycross>rectIntersection.top) && (ycross<rectIntersection.bottom)) 
			{
				return true; 
			}
			
			// and the right
			ycross = (m * cullingRectangle.right) +c;
			if((ycross>rectIntersection.top) && (ycross<rectIntersection.bottom)) 
			{
				return true; 
			}
			
		
			//nothing's crossing so no intersection!
			return false; 

		
					
					
					
			
		}
		
		
		
	}
}
